<script>
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import { atLeastN, last } from '@/utils/kris_utils'
/**
 *
 * {
    type:'picture'|('video'预留)|'upload-action'
    state:'await'|'before_uploading'|'uploading'|'success'|'failed',
    src:null|'url',
    localURL:null|'url',
    status:{
        taskId:11,
        progress:77.77
    }
* }
 */
export default {
  components: {
    'ImageViewer': ElImageViewer
  },
  props: {
    padding: {
      type: String,
      default: '6px'
    },
    bgColor: {
      type: String,
      default: ''
    },
    borderRadius: {
      type: [String, Number],
      default: 6
    },
    rowSize: {
      type: Number,
      default: 6
    },
    maxSize: {
      type: Number,
      default: 10
    },
    gapSize: {
      type: Number,
      default: 10
    },
    multiple: {
      type: Boolean,
      defualt: false
    },

    /**
         * ([{file,{onStart,onChange,onSuccess,onFailed}}])
         */
    upload: {
      type: Function
    },
    allowUpload: {
      type: Boolean,
      default: true
    },
    urls: {
      type: Array
    },

    // 同步成功的图片(暂时性的 目前没有更好的解决方案)
    pictureList: {
      type: Array,
      default() {
        return []
      }
    }
  },
  data() {
    return {
      container: {
        width: null,
        paddingLeft: null,
        paddingRight: null
      },
      imageViewer: {
        visible: false,
        zIndex: 10000,
        initialIndex: 0,
        maskClosable: true
      },
      pictures: []
    }
  },
  computed: {
    picturesFormatted() {
      const { rowSize, pictures, maxSize } = this
      const result = []
      const pictuesWithUploadAction = [...pictures]

      if (typeof this.upload === 'function' && pictures.length < maxSize) {
        pictuesWithUploadAction.push({ type: 'upload-action' })
      }

      const rowCount = Math.ceil(pictuesWithUploadAction.length / rowSize)

      for (let i = 0, offset = 0; i < rowCount; i++, offset += rowSize) {
        result.push(pictuesWithUploadAction.slice(offset, offset + rowSize))
      }
      // KRIS Debugger
      // console.log(rowCount)
      return result
    },
    picturesForViewer() {
      return this.pictures
        .filter(item => item.state === 'success')
        .map(item => {
          return item.src
        })
    },
    buildContainerStyles() {
      const { borderRadius, bgColor } = this
      return {
        borderRadius: typeof borderRadius === 'number' ? `${borderRadius}px` : borderRadius,
        padding: this.padding,
        backgroundColor: bgColor
      }
    },
    availableWidth() {
      const { gapSize, rowSize, container } = this
      return (container.width - (container.paddingLeft + container.paddingRight)) - (gapSize * (rowSize - 1))
    }
  },
  watch: {
    urls: {
      handler(urls) {
        if (!atLeastN(urls, 1)) {
          this.pictures = []
          this.syncPictureList()
          return
        }
        const pics = this.fromURLs(urls)
        this.pictures = [...pics]

        // KRIS:TEMP
        this.syncPictureList()
      },
      immediate: true
    }
  },
  mounted() {
    this.handleWindowResize()
    window.addEventListener('resize', this.handleWindowResize)
  },
  created() {
    // if(atLeastN(this.urls,1)){
    //     let pics = this.fromURLs(this.urls)
    //     this.pictures = [...pics]
    // }
    // for(let i=0;i<17;i++){
    //     this.pictures.push({
    //         type:'upload-action',
    //         state:'failed',
    //         url:'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
    //         status:{
    //             taskId:null,
    //             progress:0
    //         }
    //     })
    // }
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleWindowResize)
  },
  methods: {
    // KRIS:TEMP
    syncPictureList() {
      this.$emit(
        'update:pictureList',
        this.pictures.filter(picture => picture.state === 'success').map(picture => picture.src)
      )
    },
    clear() {
      this.pictures = []
    },
    fromURLs(urls) {
      const result = []
      for (const url of urls) {
        const picture = this.createPicture(
          'picture',
          'success',
          url,
          null,
          {
            taskId: null,
            progress: 100
          }
        )
        result.push(picture)
      }
      return result
    },
    onFileSelectorChange(e) {
      if (e.target.files.length <= 0) { return }

      const files = [...e.target.files]
      this.clearFileSelector()
      this.uploadImages(files)
    },
    clearFileSelector() {
      this.$refs.fileSelector.value = null
    },
    uploadImages(files) {
      const pictures = []
      const tasks = []
      for (const file of files) {
        if (!(file instanceof File)) { continue }

        const metadata = this.buildMetadata(file)
        const picture = this.createPicture(
          'picture',
          'await',
          null,
          metadata.localURL,
          {
            taskId: metadata.taskId,
            progress: 0
          }
        )
        const task = {
          file,
          handlers: metadata.handlers
        }

        pictures.push(picture)
        tasks.push(task)
      }

      this.pictures.push(...pictures)
            this.upload?.(tasks)
    },
    buildMetadata(file) {
      const localURL = URL.createObjectURL(file)
      const taskId = last(localURL.split('/'))
      const handlers = this.buildStatusChangeHandlers(taskId)

      if (!taskId) { throw new Error('创建任务id失败') }

      return {
        localURL,
        taskId,
        handlers
      }
    },
    createPicture(type, state, src, localURL, status) {
      return {
        type,
        state,
        src,
        localURL,
        status
      }
    },
    openImageSelector() {
            this.$refs?.fileSelector?.dispatchEvent(new MouseEvent('click'))
    },
    isPicture(col) {
      return col?.type === 'picture'
    },
    isUploadAction(col) {
      return col?.type === 'upload-action'
    },
    buildStatusChangeHandlers(taskId) {
      const findIndexByTaskId = () => {
        return this.pictures.findIndex(picture => {
          return picture.status.taskId === taskId
        })
      }

      const onStart = () => {
        const i = findIndexByTaskId()
        if (i === -1) return
        this.pictures[i].state = 'uploading'
      }

      const onChange = (progress) => {
        const i = findIndexByTaskId()
        if (i === -1) return
        this.pictures[i].status.progress = progress
      }

      const onSuccess = (url) => {
        console.log('mark', url)
        const i = findIndexByTaskId()
        if (i === -1) return
        const data = {
          ...this.pictures[i],
          state: 'success',
          src: url
        }

        this.$set(this.pictures, i, data)

        // KRIS:TEMP
        this.syncPictureList()
      }

      const onFailed = (e) => {
        const i = findIndexByTaskId()
        if (i === -1) return
        this.pictures[i].state = 'failed'
        throw new Error(e)
      }
      return {
        onStart,
        onChange,
        onSuccess,
        onFailed
      }
    },
    isAwait(item) {
      return item?.state === 'await'
    },
    isBeforeUpload(item) {
      return item?.state === 'before_uploading'
    },
    isUploading(item) {
      return item?.state === 'uploading'
    },
    isSuccess(item) {
      return item?.state === 'success'
    },
    isFail(item) {
      return item?.state === 'failed'
    },
    handleWindowResize() {
      if (!this.$refs.albumContainer) return
      const styles = getComputedStyle(this.$refs.albumContainer)
      this.container.paddingLeft = parseFloat(styles.paddingLeft)
      this.container.paddingRight = parseFloat(styles.paddingRight)
      this.container.width = this.$refs.albumContainer.offsetWidth
    },
    buildItemStyles(rowIndex, colIndex) {
      const { gapSize, rowSize, borderRadius, availableWidth } = this
      const styles = {}

      const itemWidth = availableWidth / rowSize
      styles['width'] = `${itemWidth}px`
      styles['height'] = `${itemWidth}px`
      styles['margin-left'] = colIndex === 0 ? 0 : `${gapSize}px`
      styles['margin-top'] = rowIndex === 0 ? 0 : `${gapSize}px`
      styles['border-radius'] = typeof borderRadius === 'number' ? `${borderRadius}px` : borderRadius

      // KRIS Debugger
      // console.log(styles)

      return styles
    },
    openImageViewer(rowIndex, colIndex) {
      const index = colIndex + (rowIndex * this.rowSize)
      this.imageViewer.initialIndex = index || 0
      this.imageViewer.visible = true
    },
    closeImageViewer() {
      this.imageViewer.visible = false
    },
    removePicture(rowIndex, colIndex) {
      const index = colIndex + (rowIndex * this.rowSize)
      this.pictures.splice(index, 1)

      // KRIS:TEMP
      this.syncPictureList()
    }
  }
}
</script>

<template>
  <div ref="albumContainer" class="album-container" :style="buildContainerStyles">
    <div
      v-for="(row,rowIndex) in picturesFormatted"
      :key="rowIndex"
      class="album__row"
    >
      <div
        v-for="(col,colIndex) in row"
        :key="colIndex"
        class="album__row__item"
        :style="buildItemStyles(rowIndex,colIndex)"
      >
        <template v-if="isPicture(col)">
          <!-- Success -->
          <template v-if="isSuccess(col)">
            <el-image
              class="album__row__item__image"
              :src="col.src"
              fit="cover"
              @click="openImageViewer(rowIndex,colIndex)"
            />

            <div
              class="album__row__item__delete-btn"
              @click="removePicture(rowIndex,colIndex)"
            >
              <i class="el-icon-close" />
            </div>
          </template>

          <div
            v-else
            class="cover"
            :style="{backgroundImage:`url(${col.localURL})`}"
          >
            <!-- Await / Before Uploading -->
            <div v-if="isAwait(col) || isBeforeUpload(col)" class="stateful await">
              <i class="icon el-icon-time" />
              <span class="text">等待中</span>
            </div>

            <!-- Uploading -->
            <div v-if="isUploading(col)" class="stateful uploading">
              <i class="icon el-icon-loading" />
              <span class="text">{{ col.status.progress }}%</span>
            </div>

            <!-- Failed -->
            <div v-if="isFail(col)" class="stateful fail">
              <i class="icon el-icon-warning-outline" />
              <span class="text">上传失败</span>

              <div
                class="album__row__item__delete-btn"
                style="background-color: unset;"
                @click="removePicture(rowIndex,colIndex)"
              >
                <i class="el-icon-close" />
              </div>
            </div>
          </div>
        </template>

        <!-- Upload Action -->
        <div
          v-else-if="isUploadAction"
          class="stateful upload-action"
          @click="openImageSelector"
        >
          <i class="icon el-icon-camera" />
          <span class="text">上传图片</span>
        </div>
      </div>
    </div>

    <ImageViewer
      v-if="imageViewer.visible"
      :z-index="imageViewer.zIndex"
      :initial-index="imageViewer.initialIndex"
      :on-close="closeImageViewer"
      :url-list="picturesForViewer"
    />

    <input
      ref="fileSelector"
      accept="image/*"
      type="file"
      :multiple="multiple"
      style="display: none;"
      @change="onFileSelectorChange"
    >
  </div>
</template>

<style lang="scss">
.cover {
    width: 100%;
    height: 100%;
    position: relative;
    // background-image: url(https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg);
    background-size: cover;

    .stateful {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: center;
        justify-content: center;
        // color: white;
        // background-color: rgba(0,0,0,0.25);
        font-size: 18px;
        cursor: pointer;

        .icon {
            font-size: 22px;
        }
        .text {
            font-size: 10px;
            line-height: 24px;
        }
    }

    .await,.uploading {
        color: white;
        background-color: rgba(0,0,0,0.5);
    }

    .fail {
        border: 1px dashed red;
        color: red;
        background-color: rgba(0,0,0,0.5);
    }
}

.upload-action {
    background-color: white;
    color: #8e8e8e;
    width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: center;
        justify-content: center;
        font-size: 18px;
        cursor: pointer;

        .icon {
            font-size: 22px;
        }
        .text {
            font-size: 10px;
            line-height: 24px;
        }
}

.album-container {
    background-color: #f0f0f0;
    // min-height: 100px;

    .album__row {
        display: flex;
        flex-wrap: nowrap;
        &__item {
            overflow: hidden;
            position: relative;

            &.upload-action {
                border: 2px dashed #8e8e8e;
                background-color: #eeeeee;
            }

            &__delete-btn {
                line-height: 1rem;
                background-color: #0000006b;
                color: white;
                position: absolute;
                font-size: 18px;
                top: 2px;
                right: 2px;
                border-radius: 2px;
                cursor: pointer;

            }

            &__image {
                width: 100%;
                height: 100%;
                cursor: pointer;
            }
        }
    }
}
</style>
